In [ ]:
import pandas as pd     
import matplotlib.pyplot as plt
import warnings
import numpy as np
warnings.simplefilter(action='ignore', category=FutureWarning)
import plotly.express as px
import plotly.graph_objects as go
import plotly.io as pio
pio.renderers.default='notebook'
In [ ]:
def normalize(df, how="min-max"):
    if how == "min-max" :
        return (df - df.min())/(df.max()-df.min())
    if how == "mean" :
        return (df-df.mean())/df.std()
In [ ]:
def get_cp_indices_df(df_cp, df_indices, selected_coutry = None, data_resolution = "M", normalization="mean", normalize_cp=True) :


    if not selected_coutry : selected_coutry = df_cp.country.unique()

    df_cp_filter = df_cp[df_cp.country.isin(selected_coutry) ]
    df_cp_filter = df_cp_filter.groupby([df_cp_filter.index.to_period(data_resolution)]).mean().reset_index()
    df_cp_filter = df_cp_filter.set_index(df_cp_filter.timestamp).drop(["timestamp"], axis=1)



    df_indices_filter = df_indices.groupby([df_indices.index.to_period(data_resolution)]).mean().reset_index()
    df_indices_filter = df_indices_filter.set_index(df_indices_filter.timestamp).drop(["timestamp"], axis=1)


    df_indices_filter = normalize(df_indices_filter, how=normalization)

    if normalize_cp : df_cp_filter.capacity_factor = normalize(df_cp_filter.capacity_factor, how=normalization)
    df_cp_indices = df_cp_filter.join(df_indices_filter)

    return df_cp_indices[df_cp_indices.index.year>=1982]

    

def compare_cp_index(df_cp_indices, smoothing = False, smoothing_duration=6, indices = None, start=1990, end=2019, show_plot = True):
    if indices : 
        df_cp_indices = df_cp_indices[indices+["capacity_factor"]] 
    df_cp_indices = df_cp_indices[(df_cp_indices.index.year > start) & (df_cp_indices.index.year < end)]
    if smoothing : df_cp_indices = df_cp_indices.rolling(smoothing_duration, center=True).mean()
    
    if show_plot : 
        fig = px.line(df_cp_indices.set_index(df_cp_indices.index.astype("str")), 
            title= ("normalized capacity factor and climate indices, smoothing={}".format(smoothing_duration) if smoothing else "normalized capacity factor and climate indices"))
        fig.update_traces(visible='legendonly')
        fig.update_traces(visible=True, selector=dict(name="capacity_factor"))
        fig.show()
        
    
    return df_cp_indices.corr().capacity_factor[:-1]
 
In [ ]:
df_cp = pd.read_csv("dataset_with_timestamp")
df_cp = df_cp.drop(['hour', 'month', 'year', 'day'], axis=1)
df_cp['timestamp'] = pd.to_datetime(df_cp['timestamp'], format='%Y-%m-%d %H:%M:%S')

df_cp = df_cp.groupby(["timestamp","country"]).mean().reset_index()
df_cp = df_cp.set_axis(df_cp.timestamp)
df_cp = df_cp.drop(["timestamp"], axis=1)
In [ ]:
indices = ["nao", "ao","mjo80e","mjo40w","mjo20e","mjo160e","mjo10w","nino34"]

df_indices = pd.read_csv("daily_indices_82_to_19.csv")
df_indices['timestamp'] = pd.to_datetime(df_indices['timestamp'], format='%Y-%m-%d')
df_indices = df_indices[["timestamp"]+indices]
df_indices = df_indices.set_axis(df_indices.timestamp)
df_indices = df_indices.drop(["timestamp"], axis=1)

Capacity factor and climate indices correlation :¶

Example with the UK (iso_2 : GB)¶

  • The capacity factor and the climate indices are mean normalized (standardization).
  • We work here with monthly capacity factor

Please click on the different index names to display them on the chart.

In [ ]:
selected_coutry=["GB"]
data_resolution="M" 
smoothing = False

df_cp_indices = get_cp_indices_df(df_cp, df_indices, selected_coutry=selected_coutry,data_resolution=data_resolution)
corr = compare_cp_index(df_cp_indices, indices=indices, start = 1990, show_plot= True, smoothing=smoothing)
  • We can also use the centered rolling mean over 6 months \

Please click on the different index names to display them on the chart.

In [ ]:
smoothing = True
smoothing_duration = 6
normalization = "mean"

df_cp_indices = get_cp_indices_df(df_cp, df_indices, selected_coutry=selected_coutry,data_resolution=data_resolution, normalization=normalization)
corr = compare_cp_index(df_cp_indices, indices=indices, start = 1990, show_plot= True, smoothing=smoothing, smoothing_duration= smoothing_duration )

Correlation between the 6-month rolling mean cp and the different indices :¶

In [ ]:
corr
Out[ ]:
nao        0.478359
ao         0.283468
mjo80e     0.036305
mjo40w    -0.003642
mjo20e     0.049313
mjo160e   -0.055214
mjo10w     0.026495
nino34    -0.047231
Name: capacity_factor, dtype: float64
  • As visible on the charts, nao is the most correlated.
  • Note that we did not try any time-shifting of the indices.

Comparison of the correlation monthly cp - monthly climate indices for different european countries¶

In [ ]:
smoothing = True
smoothing_duration = 6
In [ ]:
corr = dict()
for selected_country in df_cp.country.unique() :
    df_cp_indices = get_cp_indices_df(df_cp, df_indices, selected_coutry=[selected_country])
    corr[selected_country] = compare_cp_index(df_cp_indices, indices = indices, start = 1990, show_plot= False, smoothing=smoothing, smoothing_duration=smoothing_duration).to_list()

corr_df = pd.DataFrame.from_dict(corr, orient='index', columns = indices)
corr_df.index.name="country"

Correlation matrix between capacity factor and climate indices for different countries¶

In [ ]:
corr_df.style.background_gradient(vmin=-1, vmax=1,cmap='coolwarm')
Out[ ]:
  nao ao mjo80e mjo40w mjo20e mjo160e mjo10w nino34
country                
AT 0.401209 0.200381 -0.026115 0.035699 -0.007536 0.022667 0.014305 -0.100477
BE 0.357454 0.130717 0.010730 0.022674 0.061220 -0.054831 0.048417 -0.018979
BG 0.317720 -0.017226 0.054056 -0.060836 -0.068574 0.045268 -0.077557 0.010304
CH 0.358206 0.084513 -0.050144 0.077441 0.058760 -0.029234 0.078436 -0.095679
CZ 0.428832 0.269858 -0.052162 0.056053 -0.011895 0.040940 0.023017 -0.034475
DE 0.425499 0.265625 0.012558 0.009589 0.024398 -0.019538 0.018484 -0.005466
DK 0.392979 0.283005 0.118568 -0.076295 0.054574 -0.093055 -0.011928 0.020224
ES 0.144505 -0.268615 0.057807 -0.016691 0.079031 -0.094081 0.037202 0.008658
FI 0.455093 0.356469 0.073305 -0.045912 0.019648 -0.041326 -0.015784 -0.035780
FR 0.326560 0.029027 0.035180 -0.006669 0.040623 -0.045499 0.019122 0.014844
GB 0.478359 0.283468 0.036305 -0.003642 0.049313 -0.055214 0.026495 -0.047231
GR 0.147129 0.058421 0.064330 -0.023816 0.092306 -0.118249 0.042828 -0.078176
HR 0.252079 -0.086281 0.026818 0.010103 0.085786 -0.093855 0.057704 -0.110292
HU 0.309229 0.106228 -0.012991 0.034501 0.021568 -0.011096 0.031221 -0.105912
IE 0.497552 0.276609 0.060182 -0.034120 0.019501 -0.037373 -0.009001 -0.015616
IT 0.244602 -0.174834 0.050184 -0.006289 0.090978 -0.107204 0.051177 -0.122685
LT 0.379813 0.309447 0.064033 -0.016623 0.085946 -0.099994 0.041384 -0.042970
LU 0.338433 0.094717 -0.022730 0.038847 0.020475 -0.001734 0.032751 0.002173
LV 0.371548 0.330979 0.060166 -0.013994 0.089015 -0.102719 0.045047 -0.065982
ME 0.281457 -0.023618 0.042861 -0.029706 -0.001819 -0.016779 -0.018807 -0.070122
NL 0.385079 0.175133 -0.001534 0.030204 0.050473 -0.039872 0.046217 -0.039781
NO 0.489668 0.360442 0.075869 -0.056171 0.003300 -0.027937 -0.031296 -0.028138
PL 0.409841 0.330563 0.033006 -0.016295 0.003546 -0.009073 -0.008737 -0.001456
PT 0.083955 -0.313192 0.062567 -0.024090 0.058706 -0.075291 0.020393 0.051376
RO 0.334665 -0.000529 0.057750 -0.046633 -0.021992 0.001007 -0.041362 -0.027337
SE 0.466131 0.394496 0.122938 -0.080879 0.050841 -0.091888 -0.016507 -0.035804
SI 0.134383 -0.102864 0.021968 0.013913 0.105362 -0.110448 0.072288 -0.080003
SK 0.404836 0.153272 -0.024170 0.053398 0.054446 -0.036460 0.062221 -0.106471

Choropleth plot¶

Use the slider to switch between indices.

In [ ]:
melted = corr_df.melt(ignore_index=False, var_name='clim_index')
fig=px.choropleth_mapbox(melted,
        geojson="https://raw.githubusercontent.com/leakyMirror/map-of-europe/master/GeoJSON/europe.geojson",
        featureidkey='properties.ISO2',   
        locations=melted.index,        #column in dataframe
        animation_frame =melted.clim_index,       #dataframe
        color=melted.value,  #dataframe
            zoom=1, center = {"lat": 56.4, "lon": 15.0},
            mapbox_style="carto-positron",
            color_continuous_scale="Viridis",
            opacity = 0.5,
        title='Correlation between smoothened monthly capacity factor and different climate indices' ,  
        )
fig.show()

Observations :

Concerning nao and ao :

  • The nordic countries and the UK show the highest correlation values for nao and ao.
  • All countries having access to the north sea, baltic sea and the english channel show high correlation values.
  • Spain and Portugal, despite their proximity to the atlantic ocean, don't show high correlation values.

Other indices :

  • Surprisingly, mjo10w is not highly correlated to the cp
  • All the other indices don't show a high correlations

Low wind speed events¶

Example of the UK¶

In [ ]:
data_resolution = "d"
selected_country = ["GB"]
normalize_cp=False

Climate indices observed during low wind power events (cp<0.1)¶

Please click on the different index names to display them on the chart.

  • Climate indices values during low wind power events are displayed in red
  • Cp values during low wind power events are displayed in grey
In [ ]:
df_cp_indices = get_cp_indices_df(df_cp, df_indices, selected_coutry=selected_country, data_resolution=data_resolution, normalization="min-max",normalize_cp=False )
df_low_wind = df_cp_indices.copy()
df_low_wind["low_bool"] = (df_low_wind.capacity_factor<0.1)

fig = go.Figure()

fig.add_scattergl(x=df_low_wind.index.astype("str"), y=df_low_wind.capacity_factor, line={'color': 'lightgrey',"width":1},name = "capacity factor",legendgroup="cp")
fig.add_scattergl(x=df_low_wind.index.astype("str"), y=df_low_wind.capacity_factor.where(df_low_wind.low_bool), marker=dict(color='grey',size=20), showlegend=False,legendgroup="cp")


for index in indices :
    fig.add_scattergl(x=df_low_wind.index.astype("str"), y=df_low_wind[index], line={'color': 'blue',"width":1},visible="legendonly", legendgroup=index, name=index)
    fig.add_scattergl(x=df_low_wind.index.astype("str"), y=df_low_wind[index].where(df_low_wind.low_bool), line={'color': 'red',"width":2},visible="legendonly", legendgroup=index, showlegend=False)
    fig.update_layout(title="Normalized climate indices. Periods corresponding to low wind power events are highlighted in red")



fig.show()